<?php
/**
 * Created by PhpStorm.
 * Script Name: MiniTemplate.php
 * Create: 2023/02/25 下午9:36
 * Description: 版本管理
 * Author: fudaoji<fdj@kuryun.cn>
 */

namespace plugin\wechat\app\tenant\controller;

use plugin\wechat\app\model\MiniTemplateLog as TemplateLogM;
use plugin\wechat\app\model\MiniTemplateApp as TemplateAppM;
use plugin\wechat\app\service\MiniTemplate as TemplateService;
use plugin\wechat\app\service\MiniCategory as CategoryService;
use plugin\wechat\app\service\MiniSetting as SettingService;
use plugin\wechat\app\service\Mini as MiniService;
use app\common\service\Upload;
use app\common\service\App as AppService;
use think\facade\Db;
use Support\Request;

class Minitemplate extends MiniBase
{

    /**
     * @var TemplateLogM
     */
    protected $model;
    /**
     * @var TemplateAppM
     */
    protected $templateAppM;

    public function __construct()
    {
        parent::__construct(); // TODO: Change the autogenerated stub
        $this->model = new TemplateLogM();
        $this->templateAppM = new TemplateAppM();
    }

    private function tabList(){
        return [
            'index' => ['title' => '版本管理', 'href' => url('index')],
            'log' => ['title' => '历史版本', 'href' => url('log')],
        ];
    }

    /**
     * 加速审核
     * @return \support\Response
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function speedupAuditPost(){
        if(request()->isPost()){
            $post_data = input('post.');
            if(empty($post_data['auditid'])){
                return $this->error('参数错误');
            }
            if(is_string($response = TemplateService::auditSpeedUp($post_data))){
                return $this->error($response);
            }
            return $this->success('操作成功');
        }
    }

    /**
     * 发布
     * @return \support\Response
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DbException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function releasePost(){
        if(request()->isPost()){
            $id = input('post.id');
            if(is_string($response = TemplateService::release())){
                return $this->error($response);
            }
            $this->model->update([
                'id' => $id,
                'status' => TemplateService::PUBLISHED,
                'publish_time' => time()
            ]);
            return $this->success('发布成功!');
        }
    }

    /**
     * 撤销审核
     * @return \support\Response
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DbException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function cancelAuditPost(){
        // 单个帐号每天审核撤回次数最多不超过 1 次，一个月不超过 10 次。
        if(request()->isPost()){
            $id = input('post.id');
            if(is_string($response = TemplateService::auditCancel())){
                return $this->error($response);
            }
            $this->model->update(['id' => $id, 'status' => TemplateService::CANCEL]);
            return $this->success('操作成功!');
        }
    }

    /**
     * 获取审核最新信息
     * @return \support\Response
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DbException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function getAuditStatusPost(){
        if(request()->isPost()){
            $audit_id = input('post.auditid', 0);
            if(empty($audit_id)){
                return $this->error('参数错误!');
            }
            $log = $this->model->where([
                ['audit_id', '=', $audit_id],
                ['status','=', TemplateService::VERIFYING]
            ])
            ->find();
            if(empty($log)){
                return $this->success('success');
            }

            if(is_string($response = TemplateService::auditStatusGet(['auditid' => $audit_id]))){
                return $this->error($response);
            }else{
                if($response['status'] != 2){ //如果不处于审核中，则修改数据库
                    $status_dict = [
                        0 => TemplateService::SUCCESS,
                        1 => TemplateService::FAIL,
                        3 => TemplateService::CANCEL,
                        4 => TemplateService::DELAY
                    ];
                    $this->model->update([
                        'id' => $log['id'],
                        'status' => $status_dict[$response['status']],
                        'reason' => in_array($response['status'], [1, 4]) ? $response['reason'] : $log['reason']
                    ]);
                }
                return $this->success();
            }
        }
    }

    /**
     * 设置用户隐私保护协议
     * @param array $params
     * @return bool|mixed|string
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    private function setPrivacySetting($params = []){
        $response = TemplateService::privacySettingGet();
        if(is_string($response)) {
            return $response;
        }

        if($response['update_time'] == 0 || !empty($params['refresh'])){
            if(empty($config = SettingService::getAppConfig($params['app_name'],'privacy'))){
                return '请联系站长先进行隐私设置';
            }

            if(is_string($response = TemplateService::privacySettingSet($config))) {
                return $response;
            }
            return true;
        }
        return true;
    }

    /**
     * 提交审核
     * @return mixed|\support\Response
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function commitAudit(){
        $log_id = input('log_id', 0);
        $log = $this->model->where([
            $this->tenantWhere()
        ])
        ->find($log_id);

        if(request()->isPost()){
            $post_data = input('post.');
            //用户隐私保护
            if(is_string($res = $this->setPrivacySetting(['app_name' => $log['app_name'], 'refresh' => $post_data['refresh_privacy']]))){
                return $this->error($res);
            }
            $category_list = session('mini_category_list');
            $item = [];
            $ids = explode('-',$post_data['category']);
            $class_list = explode('->', $category_list[$post_data['category']]);
            $step = ['first', 'second', 'third'];
            foreach ($ids as $k => $v){
                $item[$step[$k] . '_id'] = $v;
                $item[$step[$k] . '_class'] = $class_list[$k];
                $item['address'] = $post_data['page'];
                $post_data['tags'] && $item['tag'] = implode(' ', explode(',', $post_data['tags']));
            }
            $item_list = [$item];

            $params = ['item_list' => $item_list];
            !empty($post_data['version_desc']) && $params['version_desc'] = $post_data['version_desc'];

            if(is_string($response = TemplateService::auditSubmit($params))) {
                return $this->error($response);
            }else{
                $this->model->update([
                    'id'            => $log_id,
                    'audit_id'      => $response['auditid'],
                    'extend_info'   => json_encode($item_list, JSON_UNESCAPED_UNICODE),
                    'status'        => TemplateService::VERIFYING,
                    'verify_time'   => time()
                ]);
                return $this->success('提交成功，审核需要一定时间，请耐心等待!');
            }
        }

        $assign['version_desc'] = $log['user_desc'];
        $assign['log_id'] = $log['id'];

        if(is_string($response = TemplateService::pageGet())) {
            return $this->error($response);
        }
        $assign['page'] = $response['page_list'][0];

        if(is_string($response = CategoryService::auditCategoryGet())){
            return $this->error($response);
        }else{
            $category_list = [];
            foreach ($response['category_list'] as $value){
                $id = [];
                $class = [];
                !empty($value['first_id']) && $id[] = $value['first_id'];
                !empty($value['first_class']) && $class[] = $value['first_class'];
                !empty($value['second_id']) && $id[] = $value['second_id'];
                !empty($value['second_class']) && $class[] = $value['second_class'];
                !empty($value['third_id']) && $id[] = $value['third_id'];
                !empty($value['third_class']) && $class[] = $value['third_class'];
                $category_list[implode('-', $id)] = implode('->', $class);
            }
            $assign['category_list'] = $category_list;
            session(['mini_category_list' => $category_list]);
        }

        return $this->show($assign);
    }

    /**
     * 历史版本
     * @param Request $request
     * @return mixed|\support\Response
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function log(Request $request){
        $mini_info = $request->miniInfo;
        if (request()->isPost()) {
            $post_data = input('post.');
            $where = [
                $this->tenantWhere('log'),
                ['log.mini_id', '=', $mini_info['id']]
            ];

            $query = $this->model->alias('log')
                ->where($where)
                ->join('app app', 'app.name=log.app_name');
            $total = $query->count();
            if ($total) {
                $list = $query->page($post_data['page'], $post_data['limit'])
                    ->order('log.id', 'desc')
                    ->field(['log.*', 'app.logo','app.version','app.title'])
                    ->select();
            } else {
                $list = [];
            }
            return $this->success('success', '', ['total' => $total, 'list' => $list]);
        }

        $builder = new ListBuilder();
        $builder->setTabNav($this->tabList(), __FUNCTION__)
            ->addTableColumn(['title' => '应用', 'field' => 'title', 'minWidth' => 100])
            ->addTableColumn(['title' => '最新可用版本', 'field' => 'template_id',  'minWidth' => 150])
            ->addTableColumn(['title' => '版本号', 'field' => 'user_version', 'minWidth' => 200])
            ->addTableColumn(['title' => '创建时间', 'field' => 'create_time', 'minWidth' => 180])
            ->addTableColumn(['title' => '状态', 'field' => 'status', 'type' => 'enum', 'options' => TemplateService::statusList(),'minWidth' => 180])
            ->addTableColumn(['title' => '操作', 'minWidth' => 100, 'type' => 'toolbar'])
            ->addRightButton('self', ['text' => '使用', 'data-ajax' => true, 'data-confirm' => '切换版本需要重新走代码提交、审核流程，确定吗?',
                'href' => url('useLogPost', ['id' => '__data_id__'])
                ]
            );

        return $builder->show();
    }

    /**
     * 版本管理
     * @param Request $request
     * @return mixed|\support\Response
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function index(Request $request){
        $mini_info = $request->miniInfo;
        $where = [
            $this->tenantWhere('log'),
            ['log.mini_id', '=', $mini_info['id']],
            ['log.status', '=', TemplateService::PUBLISHED]
        ];
        $publish = $this->model->alias('log')
            ->where($where)
            ->join('app app', 'app.name=log.app_name')
            ->field(['log.*', 'app.logo','app.version','app.title'])
            ->find();
        $assign['publish'] = $publish;

        $verify_where = [
            $this->tenantWhere('log'),
            ['log.mini_id', '=', $mini_info['id']],
            ['log.id', '>', empty($publish) ? 0 : $publish['id']],
            ['log.status', 'in', [TemplateService::VERIFYING, TemplateService::SUCCESS, TemplateService::FAIL, TemplateService::DELAY]]
        ];
        $verify = $this->model->alias('log')
            ->where($verify_where)
            ->join('app app', 'app.name=log.app_name')
            ->field(['log.*', 'app.logo','app.version','app.title'])
            ->order('id', 'desc')
            ->find();
        $assign['verify'] = $verify;

        $current_where = [
            $this->tenantWhere('log'),
            ['log.mini_id', '=', $mini_info['id']],
            ['log.is_current', '=', 1]
        ];
        $assign['current'] = $this->model->alias('log')
            ->where($current_where)
            ->join('app app', 'app.name=log.app_name')
            ->field(['log.*', 'app.logo','app.version','app.title'])
            ->find();

        //真实的线上版本信息
        if(is_string($response = TemplateService::getVersionInfo())){
            return $this->error($response);
        }
        $assign['real_version_info'] = $response;
        return $this->show($assign);
    }

    /**
     * 获取体验二维码
     * @author: fudaoji<fdj@kuryun.cn>
     */
    public function getTestQrCode(){
        $mini_info = \request()->miniInfo;
        if(request()->isPost()){
            $post_data = input('post.');
            $log_id = $post_data['id'];
            $log = $this->model->where([
                $this->tenantWhere()
            ])
                ->find($log_id);
            if(empty($log)){
                return $this->error('参数错误');
            }
            if(empty($log['qr_code'])){
                if(is_string($response = TemplateService::qrcodeGet())){
                    return $this->error($response);
                }else{
                    if(is_string($res = Upload::instance(dao_config('system.upload'))
                        ->putString($response['data'], 'qrcodetest_'.$mini_info['id'].'_'.time().'.png'))){
                        return $this->error($res);
                    }
                    $log = $this->model->update(['id' => $post_data['id'], 'qr_code' => $res['url']]);
                }
            }
            return $this->success('', '', ['src' => $log['qr_code']]);
        }
    }

    /**
     * 新建版本
     * @author: fudaoji<fdj@kuryun.cn>
     */
    public function choose(){
        $builder = new FormBuilder();
        $builder->setPostUrl(url('choosePost'))
            ->setTip('此操作会耗时一段时间，请勿关闭窗口')
            ->addFormItem('user_desc', 'text', '版本描述', '版本描述', [], 'required maxlength=200')
            ->addFormItem('app_name', 'choose_app', '选择应用', '', [], 'required');
        return $builder->show();
    }

    /**
     * 设置服务器域名和业务域名
     * @param array $params
     * @return bool|mixed
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    private function setDomains($params = []){
        $config = $params['config'];
        $mini_info = \request()->miniInfo;

        if(is_string($response = MiniService::domainModify($config))){
            return $response;
        }

        //2、设置业务域名
        if(!empty($config['webview_domain']) && $mini_info['principal_name'] !== '个人'){
            if(is_string($response = MiniService::webViewDomainSet($config))) {
                return $response;
            }
        }
        return true;
    }

    /**
     * 选择版本，上传代码
     * @return \support\Response
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function choosePost(){
        $mini_info = \request()->miniInfo;
        //设置服务器域名-》设置业务域名（个人号跳过此步骤）-》上传代码-》下载体验二维码
        if(request()->isPost()){
            $post_data = input('post.');
            if(empty($post_data['user_desc']) ||
                empty($post_data['app_name'])){
                return $this->error('请完善必填项', '', ['token' => token()]);
            }
            $app = AppService::getApp($post_data['app_name']);
            $post_data['user_version'] = $app['version']; //将应用的版本号作为小程序的版本号

            if(empty($config = SettingService::getAppConfig($post_data['app_name'],'domains'))){
                return $this->error('请联系站长先进行域名设置','', ['token' => token()]);
            }

            //1、设置服务器域名和业务域名
            if(is_string($res = $this->setDomains(['config' => $config]))){
                return $this->error($res,'', ['token' => token()]);
            }

            //2、隐私设置是否最新
            if(is_string($res = $this->setPrivacySetting(['app_name' => $post_data['app_name']]))){
                return $this->error($res,'', ['token' => token()]);
            }

            //3.上传代码
            $app_template = $this->templateAppM->where('app_name', $post_data['app_name'])
                ->find();

            $ext_json = SettingService::getAppConfig($post_data['app_name'], 'extjson'); //还要加其他的配置参数，例如地图key，七牛key等
            $ext_json = json_encode([
                'ext' => [
                    'appId' => $this->miniInfo['appid'],
                    'env' => array_merge(['version' => $post_data['user_version']], $ext_json),
                ]
            ]);

            $params = [
                'template_id' => $app_template['template_id'],
                'user_version' => $post_data['user_version'],
                'user_desc' => $post_data['user_desc'],
                'ext_json' => $ext_json,
            ];

            if(is_string($response = TemplateService::commit($params, $mini_info))) {
                return $this->error($response, '', ['token' => token()]);
            }else {
                //用户模板选购
                $data = [
                    'company_id'    => $mini_info['company_id'],
                    'mini_id'       => $mini_info['id'],
                    'app_name'         => $post_data['app_name'],
                    'template_id'   => $app_template['template_id'],
                    'ext_json'      => $ext_json,
                    'user_version'  => $post_data['user_version'],
                    'user_desc'     => $post_data['user_desc']
                ];
                Db::startTrans();
                try {
                    $this->model->where([
                        ['mini_id' ,'=', $mini_info['id']],
                        ['is_current','=',1]
                    ])->update(['is_current' => 0]);

                    $this->model->createOne($data);
                    Db::commit();
                    return $this->success('代码提交成功，在正式提交审核之前建议您先扫码体验', url('index'));
                }catch (\Exception $e){
                    Db::rollback();
                    return $this->error('系统出错:' . var_export($e->getMessage(), true), '', ['token' => token()]);
                }
            }
        }
    }

    /**
     * 切换到历史版本
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function useLogPost(){
        $mini_info = \request()->miniInfo;
        if(request()->isPost()){
            $log_id = input('post.id', 0);
            $log = $this->model->where([
                $this->tenantWhere()
            ])
                ->find($log_id);
            if(empty($log)){
                return $this->error('参数错误');
            }

            $ext_json = $log['ext_json']; //还要加其他的配置参数，例如地图key，七牛key等
            $params = [
                'template_id' => $log['template_id'],
                'user_version' => $log['user_version'],
                'user_desc' => $log['user_desc'],
                'ext_json' => $ext_json,
            ];

            if(is_string($response = TemplateService::commit($params, $mini_info))) {
                return $this->error($response, '', ['token' => token()]);
            }else {
                Db::startTrans();
                try {
                    $this->model->where([
                        ['mini_id' ,'=', $mini_info['id']],
                        ['is_current','=',1]
                    ])->update(['is_current' => 0]);

                    $this->model->update(['id' => $log_id, 'is_current' => 1]);
                    Db::commit();
                    return $this->success('代码提交成功，在正式提交审核之前建议您先扫码体验', url('index'));
                }catch (\Exception $e){
                    Db::rollback();
                    return $this->error('系统出错，请刷新重试', '', ['token' => token()]);
                }
            }
        }
    }
}